#include <Mutex.hh>
#include <CondVar.hh>
#include <Chain.hh>
#include <BlockingQueue.hh>
#include "QueueTest.hh"

bool QueueTest::Exit = false;
Mutex QueueTest::EnqueueKey;
Mutex QueueTest::DequeueKey;
Number QueueTest::Var = 0;
Number QueueTest::Var2 = 0;

ResultOf QueueTest::testBasicCase(BlockingQueue* Target)
{
	ResultOf Result;
	
	for (Number LC = 1; LC <= 100; LC++)
	{
		Result = Target->enqueue((void*)LC);
		checkErrorWR(Result, "Fail Target->push.");
	}
	
	for (Number LC = 1; LC <= 100; LC++)
	{
		Number Get = (Number)Target->dequeue();
		if (Get != LC)
		{
			notifyError(Get, "The resulting value is incorrect.");
			return RETURN_ERROR;
		}
	}
	
	if (Target->tellSize() != 0)
	{
		notifyError(Target->tellSize(), "Not exiting completely.");
		return RETURN_ERROR;
	}
	
	return RETURN_OK;
}

ResultOf QueueTest::testMIMO(BlockingQueue* Target)
{
	Var = 0;
	Var2 = 0;
	Exit = false;
	
	LinkedList<pthread_t>* Root;
	Root = createThread(70, enqueue, (void*)Target);
	checkNullWR(Root, "Root is NULL.");
	
	LinkedList<pthread_t>* Root2;
	Root2 = createThread(10, dequeue, (void*)Target);
	checkNullWR(Root2, "Root2 is NULL.");
	
	ResultOf Result;
	Result = destoryThread(Root);
	checkErrorWR(Result, "Fail destoryThread.");
	
	Exit = true;
	
	Result = Target->flush();
	checkErrorWR(Result, "Fail Target->waitEmpty.");
	
	Result = destoryThread(Root2);
	checkErrorWR(Result, "Fail destoryThread.");
	
	if (Var != Var2)
		{
			notifyError(Var - Var2, "The resulting value is incorrect.");
			return RETURN_ERROR;
		}
	
	if (Target->tellSize() != 0)
	{
		notifyError(Target->tellSize(), "Not exiting completely.");
		return RETURN_ERROR;
	}
	
	return RETURN_OK;
}

ResultOf QueueTest::testMIMO2(BlockingQueue* Target)
{
	Var = 0;
	Var2 = 0;
	Exit = false;
	
	ResultOf Result;
	Result = Target->fill();
	checkErrorWR(Result, "Fail Target->fill.");
	
	LinkedList<pthread_t>* Root;
	LinkedList<pthread_t>* Root2;
	
	Root = createThread(70, enqueue2, (void*)Target);
	checkNullWR(Root, "Root is NULL.");
	
	Root2 = createThread(10, dequeue2, (void*)Target);
	checkNullWR(Root2, "Root2 is NULL.");
	
	Result = destoryThread(Root);
	checkErrorWR(Result, "Fail destoryThread.");
	
	Exit = true;
	
	Result = Target->flush();
	checkErrorWR(Result, "Fail Target->waitEmpty.");
	
	Result = destoryThread(Root2);
	checkErrorWR(Result, "Fail destoryThread.");
	
	if (Var != Var2)
		{
			notifyError(Var - Var2, "The resulting value is incorrect.");
			return RETURN_ERROR;
		}
	
	if (Target->tellSize() != 0)
	{
		notifyError(Target->tellSize(), "Not exiting completely.");
		return RETURN_ERROR;
	}
	
	return RETURN_OK;
}

void* QueueTest::enqueue(void* Param)
{
	Queue* TestQueue;
	
	TestQueue = (Queue*)Param;
	for (Number LC = 1; LC <= LoopCount; LC++)
	{
		(Number)TestQueue->enqueue((void*)LC);
		
		EnqueueKey.lock();
		Var += LC;
		EnqueueKey.unlock();
	}
	
	return NULL;
}

void* QueueTest::dequeue(void* Param)
{
	Number Temp;
	Queue* TestQueue;
	
	TestQueue = (Queue*)Param;
	while (!Exit || (Temp = (Number)TestQueue->dequeue()) != 0)
	{
		DequeueKey.lock();
		Var2 += Temp;
		DequeueKey.unlock();
	}
	
	return NULL;
}

void* QueueTest::enqueue2(void* Param)
{
	Queue* TestQueue;
	
	TestQueue = (Queue*)Param;
	for (Number LC = 1; LC <= LoopCount2; LC++)
	{
		(Number)TestQueue->enqueue((void*)LC);
		
		EnqueueKey.lock();
		Var += LC;
		EnqueueKey.unlock();
		
		delay(1000);
	}
	
	return NULL;
}

void* QueueTest::dequeue2(void* Param)
{
	Number Temp;
	Queue* TestQueue;
	
	TestQueue = (Queue*)Param;
	while (!Exit || (Temp = (Number)TestQueue->dequeue()) != 0)
	{
		DequeueKey.lock();
		Var2 += Temp;
		DequeueKey.unlock();
		
		delay(1000);
	}
	
	return NULL;
}

ResultOf testQueue()
{
	ResultOf Result;
	
	QueueTest Test;
	BlockingQueue TestQueue;
	
	Result = Test.testBasicCase(&TestQueue);
	checkErrorWR(Result, "Fail Test.testBasicCase.");
	
	Result = Test.testMIMO(&TestQueue);
	checkErrorWR(Result, "Fail Test.testMIMO.");
	
	Result = Test.testMIMO2(&TestQueue);
	checkErrorWR(Result, "Fail Test.testMIMO.");
	
	fprintf(stderr, "Queue: Test success.\n");
	return RETURN_OK;
}
